using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class AsyncSocketClient
{
    private SocketAsyncEventArgs receiveArgs;
    private Socket socket;

    public void Connect(string ip, int port)
    {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        socket.Connect(new IPEndPoint(IPAddress.Parse(ip), port));

        receiveArgs = new SocketAsyncEventArgs();
        var buffer = new byte[1024];
        receiveArgs.SetBuffer(buffer, 0, buffer.Length);
        receiveArgs.Completed += ReceiveCompleted;

        StartReceive();
    }

    private void StartReceive()
    {
        var willRaiseEvent = socket.ReceiveAsync(receiveArgs);
        if (!willRaiseEvent) ProcessReceive(receiveArgs);
    }

    private void ReceiveCompleted(object sender, SocketAsyncEventArgs e)
    {
        ProcessReceive(e);
    }

    private void ProcessReceive(SocketAsyncEventArgs e)
    {
        if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
        {
            var readIndex = 0;
            while (readIndex < e.BytesTransferred)
            {
                // Read the length of the message
                var messageLength = BitConverter.ToInt32(e.Buffer, readIndex);
                readIndex += sizeof(int);

                // Read the message
                var message = Encoding.UTF8.GetString(e.Buffer, readIndex, messageLength);
                readIndex += messageLength;

                // TODO: Handle the message
            }

            // Start another receive operation
            StartReceive();
        }
        // TODO: Handle error or close
    }

    public void SendMessage(string message)
    {
        var sendArgs = new SocketAsyncEventArgs();
        var buffer = Encoding.UTF8.GetBytes(message);
        sendArgs.SetBuffer(buffer, 0, buffer.Length);
        socket.SendAsync(sendArgs);
    }
}